package com.gtlab1207.br_awareness.services;

import com.gtlab1207.br_awareness.models.dao.LogRecordDao;
import com.gtlab1207.br_awareness.models.domain.LogHost;
import com.gtlab1207.br_awareness.models.domain.LogRecord;
import com.gtlab1207.br_awareness.common.LogUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.BufferedReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import cn.hutool.core.date.DateUtil;

import static com.gtlab1207.br_awareness.common.Constant.*;

@Service
public class LogRecordService {
//    @Value("${linux.suricataCmd}")
//    private String suricataCmd;
//    @Value("${linux.securityCmd}")
//    private String securityCmd;
//    @Value("${linux.systemCmd}")
//    private String systemCmd;
    private String baseCmd = "cat ";

    @Autowired
    private LogRecordDao logRecordDao;
    @Autowired
    private LogUtil logUtil;

    /**
     * 在这执行插入操作
     * 1.获取数据
     * 2.对数据进行处理
     * 3.将数据封装成LogRecord对象
     * 4.写入数据库
     */
    @Transactional
    public void writeSuricataLog(LogHost logHost) {
        // 连接服务器
        Boolean isConnected = logUtil.connect(logHost, baseCmd+logHost.getSuricataLogPath());
        if(!isConnected)
            return;
        // 获取数据
        BufferedReader br = logUtil.getBr();

        Date preTime = DateUtil.parseDate(DateUtil.formatDate(DateUtil.offsetDay(new Date(),-7)));

        // 获取数据库中最后一条记录的时间,去掉时分秒(如果没有，就把七天前作为最后的时间)
        try {
            preTime = DateUtil.parseDate(DateUtil.formatDate(logRecordDao.selectLastLog(SURICATA_LOG).getTime()));
        } catch (NullPointerException e) {
            System.out.println("第一次操作，当前数据库为空");
        }

        String line = "";
        List<LogRecord> recordList = new ArrayList<>();
        try {
            while((line = br.readLine()) != null) {
                try {
                    // 获取当前行的日期
                    Date date = logUtil.getSuricataDate(line);
                    // 如果当前行的日期早于等于数据库最后一条的日期 就不写入
                    if (DateUtil.parseDate(DateUtil.formatDate(date)).compareTo(preTime) <= 0) {
                        continue;
                    }
                    // 在这里执行写入操作
                    LogRecord logRecord = logUtil.packSuricata(line, date);
                    //遍历已经读取的日志，如果有重复，就不写入
                    for(LogRecord i : recordList){
                        if(i.getEvent().equals(logRecord.getEvent()) && i.getDip().equals(logRecord.getDip())){
                            recordList.remove(i);//移除重复的
                            break;
                        }
                    }
                    recordList.add(logRecord);
                }catch (Exception e){
                    continue;
                }
            }
            // 写入数据库
            if(recordList.size()>0) {
                logRecordDao.insertLogList(recordList);
                System.out.println("写入成功");
            }else
                System.out.println("无新的" + SURICATA_LOG + "日志");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            try {
                if (logUtil.getConn() != null) {
                    logUtil.getConn().close();
                }
                if (logUtil.getSsh() != null) {
                    logUtil.getSsh().close();
                }
                if (br != null) {
                    br.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Transactional
    public void writeSecurityLog(LogHost logHost) {
        // 连接服务器
        Boolean isConnected = logUtil.connect(logHost, baseCmd+logHost.getSecurityLogPath());
        if(!isConnected)
            return;
        // 获取数据
        BufferedReader br = logUtil.getBr();

        Date preTime = DateUtil.parseDate(DateUtil.formatDate(DateUtil.offsetDay(new Date(),-7)));

        // 获取数据库中最后一条记录的时间,去掉时分秒(如果没有，就把七天前作为最后的时间)
        try {
            preTime = DateUtil.parseDate(DateUtil.formatDate(logRecordDao.selectLastLog(SECURITY_LOG).getTime()));
        } catch (NullPointerException e) {
            System.out.println("第一次操作，当前数据库为空");
        }

        String line = "";
        List<LogRecord> recordList = new ArrayList<>();
        try {
            while((line = br.readLine()) != null) {
                // 获取当前行的日期
                try {
                    Date date = logUtil.getSecurityDate(line);
                    // 如果当前行的日期早于等于数据库最后一条的日期 就不写入
                    if (DateUtil.parseDate(DateUtil.formatDate(date)).compareTo(preTime) <= 0) {
                        continue;
                    }
                    // 在这里执行写入操作
                    LogRecord logRecord = logUtil.packSecurity(line,date,logHost.getIpAddress());
                    //遍历已经读取的日志，如果有重复，就不写入
                    for(LogRecord i : recordList){
                        if(i.getEvent().equals(logRecord.getEvent())){
                            recordList.remove(i);//移除重复的
                            break;
                        }
                    }
                    recordList.add(logRecord);
                }catch (Exception e){
                    continue;
                }
            }
            // 写入数据库
            if(recordList.size()>0) {
                logRecordDao.insertLogList(recordList);
                System.out.println("写入成功");
            }else
                System.out.println("无新的" + SECURITY_LOG + "日志");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            try {
                if (logUtil.getConn() != null) {
                    logUtil.getConn().close();
                }
                if (logUtil.getSsh() != null) {
                    logUtil.getSsh().close();
                }
                if (br != null) {
                    br.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Transactional
    public void writeSystemLog(LogHost logHost) {
        // 连接服务器
        Boolean isConnected = logUtil.connect(logHost, baseCmd+logHost.getSystemLogPath());
        if(!isConnected)
            return;
        // 获取数据
        BufferedReader br = logUtil.getBr();

        Date preTime = DateUtil.parseDate(DateUtil.formatDate(DateUtil.offsetDay(new Date(),-7)));

        // 获取数据库中最后一条记录的时间,去掉时分秒(如果没有，就把七天前作为最后的时间)
        try {
            preTime = DateUtil.parseDate(DateUtil.formatDate(logRecordDao.selectLastLog(SYSTEM_LOG).getTime()));
        } catch (NullPointerException e) {
            System.out.println("第一次操作，当前数据库为空");
        }

        List<LogRecord> recordList = new ArrayList<>();
        LogRecord tempLogRecord = new LogRecord();
        tempLogRecord.setType(SYSTEM_LOG);
        tempLogRecord.setDip(logHost.getIpAddress());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String line = "";
        try {
            while((line = br.readLine()) != null) {
                //用正则截取出时间字段
                String regex = "\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}";
                Pattern p = Pattern.compile(regex);
                Matcher matcher = p.matcher(line);
                if (matcher.find()) {
                    String timeStr = matcher.group(0);
                    // 获取当前行的日期
                    Date date = sdf.parse(timeStr);
                    // 如果当前行的日期早于等于数据库最后一条的日期 就不写入
                    if (DateUtil.parseDate(DateUtil.formatDate(date)).compareTo(preTime) <= 0) {
                        continue;
                    }
                    tempLogRecord.setTime(date);
                    System.out.println("时间:" + timeStr);
                }
                //截取异常原因
                String strStart = "Caused by:";
                // 找出指定字符串在该字符串里面的位置
                int strStartIndex = line.indexOf(strStart);
                //判断是否有指定的内容
                if (strStartIndex >= 0) {
                    // 开始截取
                    String event = line.substring(strStartIndex).substring(strStart.length());
                    if(tempLogRecord.getTime()!=null && tempLogRecord.getEvent()==null) {
                        tempLogRecord.setEvent(event);
                        System.out.println("截取的异常原因：" + event);
                    }
                }

                if(tempLogRecord.getTime()!=null && tempLogRecord.getEvent()!=null) {
                    //遍历已经读取的日志，如果有重复，就不写入
                    for(LogRecord i : recordList){
                        if(i.getEvent().equals(tempLogRecord.getEvent())){
                            recordList.remove(i);//移除重复的
                            break;
                        }
                    }
                    recordList.add(tempLogRecord);
                    System.out.println("截取后的提取的数据=====" + tempLogRecord);
                    tempLogRecord = new LogRecord();
                    tempLogRecord.setType(SYSTEM_LOG);
                    tempLogRecord.setDip(logHost.getIpAddress());
                }

            }
            // 写入数据库
            if(recordList.size()>0) {
                logRecordDao.insertLogList(recordList);
                System.out.println("写入成功");
            }else
                System.out.println("无新的" + SYSTEM_LOG + "日志");
        } catch (IOException | ParseException e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            try {
                if (logUtil.getConn() != null) {
                    logUtil.getConn().close();
                }
                if (logUtil.getSsh() != null) {
                    logUtil.getSsh().close();
                }
                if (br != null) {
                    br.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //查询所有日志消息
    public List<LogRecord> showAllLogs(){
        return logRecordDao.showAllLogs();
    };
    // 查询数据库最近七天的事件记录
    public List<LogRecord> selectEventInSevenDay(){
        return logRecordDao.selectEventInSevenDay();
    }

    //写入前删除大于七天的数据
    public void deleteLogRecord(){
        logRecordDao.deleteLogRecord();
    }

}

